//
//  FCrash.m
//  FFoundation
//
//  Created by 三井 on 2021/6/30.
//

#import "FCrash.h"
#import "FTestHeaders.h"

typedef void (*SignalHandler)(int signo, siginfo_t *info, void *context);
static SignalHandler previousSignalHandler = NULL;
static NSUncaughtExceptionHandler *previousExceptionHandler = NULL;

static void FCarshSignalHandler(int signal, siginfo_t* info, void* context) {
    FTestLogError(@"%@", @"Crashed");
    
    if (previousSignalHandler) {
        previousSignalHandler(signal, info, context);
    }
}

// Exception Handle
static void FCrashExceptionHandler(NSException *e) {
    FTestLogError(@"%@", e);
    
    if (previousExceptionHandler) {
        previousExceptionHandler(e);
    }
}

@implementation FCrash

+ (void)install {
    struct sigaction oldAction;
    sigaction(SIGABRT, NULL, &oldAction);
    if (oldAction.sa_mask & SA_SIGINFO) {
        previousSignalHandler = oldAction.sa_sigaction;
    }
    
    struct sigaction action = [self actionForSig:SIGABRT];
    sigaction(SIGABRT, &action, NULL);
    
    // Exceptions
    previousExceptionHandler = NSGetUncaughtExceptionHandler();
    NSSetUncaughtExceptionHandler(FCrashExceptionHandler);
}

+ (struct sigaction)actionForSig:(int)sig {
    struct sigaction action;
    action.sa_flags = SA_NODEFER | SA_SIGINFO;
    action.sa_sigaction = FCarshSignalHandler;
    sigemptyset(&action.sa_mask);
    return action;
}

@end
